package com.citybiz.system.service.biz.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.citybiz.common.constant.TaskConstant;
import com.citybiz.common.enums.biz.BizPayPlanStageEnum;
import com.citybiz.common.enums.biz.BizPlayStageStatusEnum;
import com.citybiz.common.enums.biz.BizTaskStatusEnum;
import com.citybiz.common.enums.biz.TenderTaskStatusEnum;
import com.citybiz.common.exception.ServiceException;
import com.citybiz.common.utils.AssertUtils;
import com.citybiz.common.utils.bean.BeanUtils;
import com.citybiz.system.domain.biz.BizPayPlan;
import com.citybiz.system.domain.biz.BizTaskConsign;
import com.citybiz.system.domain.biz.BizTaskExtendInfo;
import com.citybiz.system.domain.dto.BizPayPlanDTO;
import com.citybiz.system.domain.dto.BizTaskConsignDTO;
import com.citybiz.system.domain.dto.BizTaskDto;
import com.citybiz.system.domain.dto.BizTaskExtendInfoDTO;
import com.citybiz.system.domain.request.BizTaskRequest;
import com.citybiz.system.mapper.biz.BizPayPlanPlusMapper;
import com.citybiz.system.mapper.biz.BizTaskConsignMapper;
import com.citybiz.system.mapper.biz.BizTaskExtendInfoPlusMapper;
import com.citybiz.system.service.biz.IBizTaskPayPlanService;
import com.citybiz.system.service.biz.IBizTaskService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * Create by Ykg on 2024/2/11 17:51
 * effect: 任务付款计划服务类
 */
@Service
@AllArgsConstructor
@Slf4j
public class BizTaskPayPlanServiceImpl implements IBizTaskPayPlanService {

    private BizPayPlanPlusMapper bizPayPlanPlusMapper;

    private IBizTaskService bizTaskService;

    private BizTaskExtendInfoPlusMapper bizTaskExtendInfoPlusMapper;

    private BizTaskConsignMapper bizTaskConsignMapper;

    @Override
    public void addPayPlan(BizPayPlanDTO bizPayPlanDTO) {
        Long taskId = bizPayPlanDTO.getTaskId();
        BizTaskDto bizTaskDto = bizTaskService.selectBizTaskById(taskId);
        if(bizTaskDto == null){
            throw new ServiceException("任务不存在，请确认");
        }
        String taskStatus = bizTaskDto.getTaskStatus();
        String tenderTaskStatus = bizTaskDto.getTenderTaskStatus();
        if(!taskStatus.equals(BizTaskStatusEnum.WORKING.getCode())){
            throw new ServiceException("非工作中状态，请确认");
        }
        if(!tenderTaskStatus.equals(TenderTaskStatusEnum.COUNSEL_PAY_PLAN.getCode())){
            throw new ServiceException("非商议付款阶段，请确认");
        }

        String planStage = bizPayPlanDTO.getPlanStage();
        BizPayPlanStageEnum anEnum = BizPayPlanStageEnum.getEnum(planStage);
        if (anEnum == null) {
            throw new ServiceException("阶段错误，请确认");
        }
        LambdaQueryWrapper<BizPayPlan> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(BizPayPlan::getPlanStage, planStage);
        wrapper.eq(BizPayPlan::getTaskId, bizPayPlanDTO.getTaskId());
        BizPayPlan stageBizPayPlan = bizPayPlanPlusMapper.selectOne(wrapper);
        if (stageBizPayPlan != null) {
            throw new ServiceException("该任务下只能有一个:" + anEnum.getMsg());
        }

        BizPayPlan insert = new BizPayPlan();
        BeanUtils.copyProperties(bizPayPlanDTO, insert);
        insert.setStageStatus(BizPlayStageStatusEnum.NOT_HOSTED.getCode());
        bizPayPlanPlusMapper.insert(insert);
    }

    @Override
    public void updatePayPlan(BizPayPlanDTO bizPayPlanDTO) {
        String planStage = bizPayPlanDTO.getPlanStage();
        BizPayPlanStageEnum anEnum = BizPayPlanStageEnum.getEnum(planStage);
        if (anEnum == null) {
            throw new ServiceException("阶段错误，请确认");
        }
        LambdaQueryWrapper<BizPayPlan> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(BizPayPlan::getPlanStage, planStage);
        wrapper.eq(BizPayPlan::getTaskId, bizPayPlanDTO.getTaskId());
        BizPayPlan stageBizPayPlan = bizPayPlanPlusMapper.selectOne(wrapper);
        if (stageBizPayPlan != null) {
            throw new ServiceException("该任务下只能有一个:" + anEnum.getMsg());
        }

        BizPayPlan update = new BizPayPlan();
        BeanUtils.copyProperties(bizPayPlanDTO, update);
        update.setStageStatus(BizPlayStageStatusEnum.NOT_HOSTED.getCode());
        bizPayPlanPlusMapper.updateById(update);
    }

    @Override
    public void submitPayPlan(Long taskId) {
        BizTaskDto bizTaskDto = bizTaskService.selectBizTaskById(taskId);
        if (bizTaskDto == null) {
            throw new ServiceException("任务不存在，请确认");
        }
        String taskStatus = bizTaskDto.getTaskStatus();
        String tenderTaskStatus = bizTaskDto.getTenderTaskStatus();
        if(!taskStatus.equals(BizTaskStatusEnum.WORKING.getCode())){
            throw new ServiceException("非工作中状态，请确认");
        }

        if(!(tenderTaskStatus.equals(TenderTaskStatusEnum.COUNSEL_PAY_PLAN.getCode())
                || tenderTaskStatus.equals(TenderTaskStatusEnum.REJECT_PAY_PLAN.getCode()))){
            throw new ServiceException("非商议付款阶段，请确认");
        }


        LambdaQueryWrapper<BizPayPlan> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(BizPayPlan::getTaskId, taskId);
        List<BizPayPlan> bizPayPlans =
                bizPayPlanPlusMapper.selectList(wrapper);

        if (CollectionUtils.isEmpty(bizPayPlans) || bizPayPlans.size() != 3) {
            throw new ServiceException("任务下付款信息未完善，请确认");
        }

        int allProp = 0;
        for (BizPayPlan bizPayPlan : bizPayPlans) {
            Integer payProp = bizPayPlan.getPayProp();
            allProp += payProp;
        }

        if (allProp != 100) {
            throw new ServiceException("付款比例总和非100%，请确认");
        }
        BizTaskRequest request = new BizTaskRequest();
        request.setTenderTaskStatus(TenderTaskStatusEnum.TO_BE_CONFIRMED.getCode());
        request.setTaskId(bizTaskDto.getId());
        bizTaskService.updateBizTask(request);
    }

    @Override
    @Transactional
    public void confirmPayPlan(Long taskId, String remark, Integer confirmFlag) {
        BizTaskDto bizTaskDto = bizTaskService.selectBizTaskById(taskId);
        if (bizTaskDto == null) {
            throw new ServiceException("任务不存在，请确认");
        }

        String taskStatus = bizTaskDto.getTaskStatus();
        String tenderTaskStatus = bizTaskDto.getTenderTaskStatus();
        if(!taskStatus.equals(BizTaskStatusEnum.WORKING.getCode())){
            throw new ServiceException("非工作中状态，请确认");
        }
        if(!tenderTaskStatus.equals(TenderTaskStatusEnum.TO_BE_CONFIRMED.getCode())){
            throw new ServiceException("非待确认付款阶段，请确认");
        }

        BizTaskRequest request = new BizTaskRequest();
        request.setTaskId(taskId);
        if (confirmFlag == 1) {
            request.setTenderTaskStatus(TenderTaskStatusEnum.WAIT_TO_HOST_PRE_PAYED.getCode());
        }

        if (confirmFlag == 0) {
            request.setTenderTaskStatus(TenderTaskStatusEnum.REJECT_PAY_PLAN.getCode());
            AssertUtils.isNotEmpty(remark, "备注信息不可为空");
            BizTaskExtendInfoDTO taskExtend = bizTaskService.getTaskExtend(taskId);
            taskExtend.setContext(TaskConstant.rejectPayPlanRemark, remark);
            bizTaskService.updateTaskExtend(taskExtend);
        }
        bizTaskService.updateBizTask(request);
    }

    @Override
    @Transactional
    public void hostingPayPlanAmount(Long taskPayPlanId, BigDecimal payAmount) {
        BizPayPlan bizPayPlan = bizPayPlanPlusMapper.selectById(taskPayPlanId);
        if (bizPayPlan == null) {
            throw new ServiceException("支付计划不存在");
        }
        Long taskId = bizPayPlan.getTaskId();

        if(!bizPayPlan.getStageStatus().equals(BizPlayStageStatusEnum.NOT_HOSTED.getCode())){
            throw new ServiceException("状态非未托管，请确认");
        }

        BizTaskDto bizTaskDto = bizTaskService.selectBizTaskById(bizPayPlan.getTaskId());
        if(bizTaskDto == null){
            throw new ServiceException("任务不存在，请确认");
        }

        BizTaskRequest request = new BizTaskRequest();
        request.setTaskId(bizPayPlan.getTaskId());

        // 预支付阶段控制
        if(bizPayPlan.getPlanStage().equals(BizPayPlanStageEnum.PRE_PAY_STAGE.getCode())) {
            if(!bizTaskDto.getTenderTaskStatus().equals(TenderTaskStatusEnum.WAIT_TO_HOST_PRE_PAYED.getCode())){
                throw new ServiceException("非待托付预付款阶段，请确认");
            }
            request.setTenderTaskStatus(TenderTaskStatusEnum.WAIT_TO_PAY_PRE_PAYED.getCode());
        }

        // 工作阶段流程控制
        if(bizPayPlan.getPlanStage().equals(BizPayPlanStageEnum.WORKER_STAGE.getCode())){
            if(!bizTaskDto.getTenderTaskStatus().equals(TenderTaskStatusEnum.WAIT_TO_HOST_PROJECT_PAYED.getCode())){
                throw new ServiceException("非待托付工程款阶段，请确认");
            }
            LambdaQueryWrapper<BizPayPlan> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(BizPayPlan::getTaskId,taskId)
                    .eq(BizPayPlan::getPlanStage,BizPayPlanStageEnum.PRE_PAY_STAGE.getCode());
            BizPayPlan prePayStagePlan = bizPayPlanPlusMapper.selectOne(wrapper);
            if(!prePayStagePlan.getStageStatus().equals(BizPlayStageStatusEnum.PAID.getCode())){
                throw new ServiceException("预付阶段未进行支付，请确认");
            }
            request.setTenderTaskStatus(TenderTaskStatusEnum.WAIT_DELIVERY.getCode());
        }

        // 售后阶段流程控制
        if(bizPayPlan.getPlanStage().equals(BizPayPlanStageEnum.AFTER_SALES_STAGE.getCode())){
            if(!bizTaskDto.getTenderTaskStatus().equals(TenderTaskStatusEnum.WAIT_TO_HOST_PRE_AFTER_SALES_PAYED.getCode())){
                throw new ServiceException("非待托付售后款阶段，请确认");
            }
            LambdaQueryWrapper<BizPayPlan> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(BizPayPlan::getTaskId,taskId)
                    .eq(BizPayPlan::getPlanStage,BizPayPlanStageEnum.WORKER_STAGE.getCode());
            BizPayPlan workerStage = bizPayPlanPlusMapper.selectOne(wrapper);
            if(!workerStage.getStageStatus().equals(BizPlayStageStatusEnum.ACCEPTANCE_SUCCESS.getCode())){
                throw new ServiceException("工作阶段未验收成功，请确认");
            }
            request.setTenderTaskStatus(TenderTaskStatusEnum.WAIT_TO_HOST_PRE_AFTER_SALES_PAYED.getCode());
        }

        if (bizPayPlan.getPlanStage().equals(BizPayPlanStageEnum.WORKER_STAGE.getCode())) {
            bizPayPlan.setStageStatus(BizPlayStageStatusEnum.TO_BE_DELIVERED.getCode());
        } else {
            bizPayPlan.setStageStatus(BizPlayStageStatusEnum.HOSTED.getCode());
        }
        bizTaskService.updateBizTask(request);
        bizPayPlanPlusMapper.updateById(bizPayPlan);
    }

    @Override
    public void payPlanAmount(Long taskPayPlanId, BigDecimal payAmount) {
        BizPayPlan bizPayPlan = bizPayPlanPlusMapper.selectById(taskPayPlanId);
        if (bizPayPlan == null) {
            throw new ServiceException("支付计划不存在");
        }

        if(bizPayPlan.getPlanStage().equals(BizPayPlanStageEnum.WORKER_STAGE.getCode())){
            throw new ServiceException("工作阶段无法直接支付，请确认");
        }

        BizTaskRequest request = new BizTaskRequest();
        request.setTaskId(bizPayPlan.getTaskId());

        // 预付阶段流程控制
        if(bizPayPlan.getPlanStage().equals(BizPayPlanStageEnum.PRE_PAY_STAGE.getCode())){
            Long taskId = bizPayPlan.getTaskId();
            LambdaQueryWrapper<BizPayPlan> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(BizPayPlan::getTaskId,taskId)
                    .eq(BizPayPlan::getPlanStage,BizPayPlanStageEnum.PRE_PAY_STAGE.getCode());
            BizPayPlan prePayStagePlan = bizPayPlanPlusMapper.selectOne(wrapper);
            if(!prePayStagePlan.getStageStatus().equals(BizPlayStageStatusEnum.HOSTED.getCode())){
                throw new ServiceException("预付阶段未托管金额，请确认");
            }
            request.setTenderTaskStatus(TenderTaskStatusEnum.WAIT_DELIVERY.getCode());
        }

        // 售后阶段流程控制
        if(bizPayPlan.getPlanStage().equals(BizPayPlanStageEnum.AFTER_SALES_STAGE.getCode())){
            Long taskId = bizPayPlan.getTaskId();
            LambdaQueryWrapper<BizPayPlan> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(BizPayPlan::getTaskId,taskId)
                    .eq(BizPayPlan::getPlanStage,BizPayPlanStageEnum.AFTER_SALES_STAGE.getCode());
            BizPayPlan afterSalesPlan = bizPayPlanPlusMapper.selectOne(wrapper);
            if(!afterSalesPlan.getStageStatus().equals(BizPlayStageStatusEnum.HOSTED.getCode())){
                throw new ServiceException("售后阶段未托管金额，请确认");
            }
            request.setTenderTaskStatus(TenderTaskStatusEnum.TASK_END.getCode());
            request.setTaskStatus(BizTaskStatusEnum.EVALUATING.getCode());
        }
        bizPayPlan.setStageStatus(BizPlayStageStatusEnum.PAID.getCode());
        bizTaskService.updateBizTask(request);
        bizPayPlanPlusMapper.updateById(bizPayPlan);
    }

    @Override
    @Transactional
    public void consignWorker(BizTaskConsignDTO bizTaskConsignDTO) {
        Long taskId = bizTaskConsignDTO.getTaskId();
        Long taskPayPlanId = bizTaskConsignDTO.getTaskPayPlanId();
        BizTaskDto bizTaskDto = bizTaskService.selectBizTaskById(taskId);
        BizPayPlan bizPayPlan = bizPayPlanPlusMapper.selectById(taskPayPlanId);
        if(bizTaskDto ==  null){
            throw new ServiceException("任务不存在，请确认");
        }
        if(!bizTaskDto.getTenderTaskStatus().equals(TenderTaskStatusEnum.WAIT_DELIVERY.getCode())){
            throw new ServiceException("非待交付状态，请确认");
        }
        if (!bizTaskDto.getId().equals(bizPayPlan.getTaskId())) {
            throw new ServiceException("招标任务与交付阶段信息不匹配，请确认");
        }

        if (!bizPayPlan.getPlanStage().equals(BizPayPlanStageEnum.WORKER_STAGE.getCode())) {
            throw new ServiceException("请在工作阶段交付文件");
        }
        // 升级任务状态
        BizTaskConsign insert = new BizTaskConsign();
        BeanUtils.copyProperties(bizTaskConsignDTO, insert);
        insert.setCreateTime(new Date());
        bizTaskConsignMapper.insert(insert);
        bizPayPlan.setStageStatus(BizPlayStageStatusEnum.TO_BE_ACCEPTED.getCode());
        BizTaskRequest request = new BizTaskRequest();
        request.setTaskId(bizPayPlan.getTaskId());
        request.setTenderTaskStatus(TenderTaskStatusEnum.WAIT_DELIVERY_ACCEPTANCE.getCode());
        bizTaskService.updateBizTask(request);
        bizPayPlanPlusMapper.updateById(bizPayPlan);
    }

    @Override
    public void confirmConsign(Long taskPayPlanId) {
        BizPayPlan bizPayPlan = bizPayPlanPlusMapper.selectById(taskPayPlanId);
        if (bizPayPlan == null) {
            throw new ServiceException("工作阶段的交付");
        }
        Long taskId = bizPayPlan.getTaskId();
        BizTaskDto bizTaskDto = bizTaskService.selectBizTaskById(taskId);
        if(!bizTaskDto.getTenderTaskStatus().equals(TenderTaskStatusEnum.WAIT_DELIVERY_ACCEPTANCE.getCode())){
            throw new ServiceException("作品未交付，请确认");
        }
        bizPayPlan.setStageStatus(BizPlayStageStatusEnum.ACCEPTANCE_SUCCESS.getCode());

        BizTaskRequest request = new BizTaskRequest();
        request.setTaskId(taskId);
        request.setTenderTaskStatus(TenderTaskStatusEnum.WAIT_TO_HOST_PRE_AFTER_SALES_PAYED.getCode());
        bizTaskService.updateBizTask(request);
        bizPayPlanPlusMapper.updateById(bizPayPlan);
    }

    @Override
    public List<BizPayPlanDTO> getPayPlanListForTaskId(Long taskId) {
        LambdaQueryWrapper<BizPayPlan> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(BizPayPlan::getTaskId, taskId);
        List<BizPayPlan> bizPayPlans = bizPayPlanPlusMapper.selectList(wrapper);
        return convert(bizPayPlans);
    }

    private BizPayPlanDTO convert(BizPayPlan bizPayPlan) {
        BizPayPlanDTO result = new BizPayPlanDTO();
        if (bizPayPlan == null) {
            return null;
        }
        BeanUtils.copyProperties(bizPayPlan, result);
        return result;
    }

    private List<BizPayPlanDTO> convert(List<BizPayPlan> bizPayPlanList) {
        if (CollectionUtils.isEmpty(bizPayPlanList)) {
            return new ArrayList<>();
        }

        return bizPayPlanList.stream()
                .map(this::convert)
                .collect(Collectors.toList());
    }
}
